package org.jeecg.pms.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.hutool.core.date.DateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.autopoi.poi.excel.ExcelImportUtil;
import org.jeecg.autopoi.poi.excel.entity.ImportParams;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.online.config.exception.BusinessException;
import org.jeecg.pms.entity.PmsProject;
import org.jeecg.pms.entity.PmsTask;
import org.jeecg.pms.entity.PmsTaskTime;
import org.jeecg.pms.mapper.PmsTaskMapper;
import org.jeecg.pms.service.IPmsProjectService;
import org.jeecg.pms.service.IPmsTaskService;
import org.jeecg.pms.service.IPmsTaskTimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Service
public class PmsTaskService extends ServiceImpl<PmsTaskMapper, PmsTask> implements IPmsTaskService {

	@Autowired
	private IPmsTaskService pmsTaskService;

	@Autowired
	private IPmsTaskTimeService pmsTaskTimeService;
    @Autowired
    private IPmsProjectService pmsProjectService;


    private String PMS_TASK_TYPE = "project";

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void addPmsTask(PmsTask pmsTask) {
	    pmsTask.setTaskType(PMS_TASK_TYPE);
	    pmsTask.setEndTime(DateUtil.offsetSecond(DateUtil.endOfDay(pmsTask.getEndTime()), -1));
		if(oConvertUtils.isEmpty(pmsTask.getParentTaskCode())){
			pmsTask.setParentTaskCode(IPmsTaskService.ROOT_PID_VALUE);
		}else{
			//如果当前节点父ID不为空 则设置父节点的hasChildren 为1
			PmsTask parent;
			try{
				parent = pmsTaskService.getOne(new QueryWrapper<PmsTask>().eq("task_code", pmsTask.getParentTaskCode()));
				if(parent!=null && !"1".equals(parent.getHasChildren())){
					parent.setHasChildren("1");
					pmsTaskService.updateById(parent);
				}
			}catch (Exception e) {

			}
		}
		baseMapper.insert(pmsTask);
		pmsTaskService.computeTaskTime(pmsTask.getProjectCode());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updatePmsTask(PmsTask pmsTask) {
		PmsTask entity = this.getById(pmsTask.getId());
		if(entity==null) {
			throw new JeecgBootException("未找到对应实体");
		}
		String old_pid = entity.getParentTaskCode();
		String new_pid = pmsTask.getParentTaskCode();
		if(!old_pid.equals(new_pid)) {
			updateOldParentNode(old_pid);
			if(oConvertUtils.isEmpty(new_pid)){
				pmsTask.setParentTaskCode(IPmsTaskService.ROOT_PID_VALUE);
			}
			if(!IPmsTaskService.ROOT_PID_VALUE.equals(pmsTask.getParentTaskCode())) {
				baseMapper.updateTreeNodeStatus(pmsTask.getParentTaskCode(), IPmsTaskService.HASCHILD);
			}
		}
        pmsTask.setEndTime(DateUtil.offsetSecond(DateUtil.endOfDay(pmsTask.getEndTime()), -1));
		baseMapper.updateById(pmsTask);
		computeTaskTime(pmsTask.getProjectCode());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deletePmsTask(String code) throws JeecgBootException {
		//查询选中节点下所有子节点一并删除
		code = this.queryTreeChildCodes(code);
        if(code.indexOf(",")>0) {
            StringBuffer sb = new StringBuffer();
            String[] codeArr = code.split(",");
            for (String codeVal : codeArr) {
                if(codeVal != null){
                    PmsTask pmsTask = this.getOne(new QueryWrapper<PmsTask>().eq("task_code", codeVal));
                    String pcodeVal = pmsTask.getParentTaskCode();
                    //查询此节点上一级是否还有其他子节点
                    List<PmsTask> dataList = baseMapper.selectList(new QueryWrapper<PmsTask>().eq("parent_task_code", pcodeVal).notIn("task_code",Arrays.asList(codeArr)));
                    if((dataList == null || dataList.size()==0) && !Arrays.asList(codeArr).contains(pcodeVal)
                            && !sb.toString().contains(pcodeVal)){
                        //如果当前节点原本有子节点 现在木有了，更新状态
                        sb.append(pcodeVal).append(",");
                    }
                }
            }
            //批量删除节点
            baseMapper.delete(new QueryWrapper<PmsTask>().in("task_code", Arrays.asList(codeArr)));
            //修改已无子节点的标识
            String[] pcodeArr = sb.toString().split(",");
            for(String pcode : pcodeArr){
                this.updateOldParentNode(pcode);
            }
        }else{
            PmsTask pmsTask = this.getOne(new QueryWrapper<PmsTask>().eq("task_code",code));
            if(pmsTask==null) {
                throw new JeecgBootException("未找到对应实体");
            }
            updateOldParentNode(pmsTask.getParentTaskCode());
            baseMapper.deleteById(pmsTask.getId());
        }
	}

	@Override
    public List<PmsTask> queryTreeListNoPage(QueryWrapper<PmsTask> queryWrapper) {
        List<PmsTask> dataList = baseMapper.selectList(queryWrapper);
        List<PmsTask> mapList = new ArrayList<>();
        for(PmsTask data : dataList){
            String pidVal = data.getParentTaskCode();
            //递归查询子节点的根节点
            if(pidVal != null && !"0".equals(pidVal)){
                PmsTask rootVal = this.getTreeRoot(pidVal);
                if(rootVal != null && !mapList.contains(rootVal)){
                    mapList.add(rootVal);
                }
            }else{
                if(!mapList.contains(data)){
                    mapList.add(data);
                }
            }
        }
        return mapList;
    }

	/**
	 * 根据所传pcode查询旧的父级节点的子节点并修改相应状态值
	 * @param pcode
	 */
	private void updateOldParentNode(String pcode) {
		if(!IPmsTaskService.ROOT_PID_VALUE.equals(pcode)) {
			Integer count = baseMapper.selectCount(new QueryWrapper<PmsTask>().eq("parent_task_code", pcode));
			if(count==null || count<=1) {
				baseMapper.updateTreeNodeStatus(pcode, IPmsTaskService.NOCHILD);
			}
		}
	}

	/**
     * 递归查询节点的根节点
     * @param pidVal
     * @return
     */
    private PmsTask getTreeRoot(String pcodeVal){
        PmsTask data =  baseMapper.selectOne(new QueryWrapper<PmsTask>().eq("task_code", pcodeVal));
        if(data != null && !"0".equals(data.getParentTaskCode())){
            return this.getTreeRoot(data.getParentTaskCode());
        }else{
            return data;
        }
    }

    /**
     * 根据code查询所有子节点code
     * @param codes
     * @return
     */
    private String queryTreeChildCodes(String codes) {
        //获取id数组
        String[] codeArr = codes.split(",");
        StringBuffer sb = new StringBuffer();
        for (String pcodeVal : codeArr) {
            if(pcodeVal != null){
                if(!sb.toString().contains(pcodeVal)){
                    if(sb.toString().length() > 0){
                        sb.append(",");
                    }
                    sb.append(pcodeVal);
                    this.getTreeChildCodes(pcodeVal,sb);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 递归查询所有子节点
     * @param pcodeVal
     * @param sb
     * @return
     */
    private StringBuffer getTreeChildCodes(String pcodeVal,StringBuffer sb){
        List<PmsTask> dataList = baseMapper.selectList(new QueryWrapper<PmsTask>().eq("parent_task_code", pcodeVal));
        if(dataList != null && dataList.size()>0){
            for(PmsTask tree : dataList) {
                if(!sb.toString().contains(tree.getTaskCode())){
                    sb.append(",").append(tree.getTaskCode());
                }
                this.getTreeChildCodes(tree.getTaskCode(),sb);
            }
        }
        return sb;
    }

	/*@Override
	public List<PmsTask> queryTreeList(List<PmsTask> list) {
		List<PmsTask> resultList = new ArrayList<>();
		for(PmsTask task : list){
			PmsTask newTask = toTree(task);
			resultList.add(newTask);
		}
		return resultList;
	}

	private PmsTask toTree(PmsTask task){
		if(task.getHasChildren() !=null && "1".equals(task.getHasChildren())){
			QueryWrapper<PmsTask> qw = new QueryWrapper<>();
			qw.eq("parent_task_code", task.getTaskCode());
			List<PmsTask> subList = baseMapper.selectList(qw);
			List<PmsTask> newSubList = new ArrayList<>();
			if(!CollectionUtils.isEmpty(subList)){
				for(PmsTask subTask : subList){
					PmsTask newTask = toTree(subTask);
					newSubList.add(newTask);
				}
			}

			task.setChildren(newSubList);
		}
		return task;
	}*/

    @Override
	public List<PmsTask> queryTreeList(List<PmsTask> list) {
		for(PmsTask task : list){
			this.handleTransientVariable(task);
			// 递归生成树
			toTree(task);
		}
		return list;
	}

    public void handleTransientVariable(PmsTask task){
    	QueryWrapper<PmsTaskTime> qw = new QueryWrapper<>();
    	qw.eq("task_code", task.getTaskCode());
    	List<PmsTaskTime> list = pmsTaskTimeService.list(qw);
    	BigDecimal actualManHours = BigDecimal.ZERO;
    	if(list != null){
            for(PmsTaskTime taskTime : list){
    			if(taskTime.getManHours() != null){
                    actualManHours = actualManHours.add(taskTime.getManHours());
                }
//    			if (DateUtil.isSameDay(taskTime.getStartTime(),task.get)
        	}
    	}
    	task.setActualManHours(actualManHours);
    }

    // 递归生成树
	private PmsTask toTree(PmsTask task){
		if(task.getHasChildren() !=null && "1".equals(task.getHasChildren())){
			QueryWrapper<PmsTask> qw = new QueryWrapper<>();
			qw.eq("parent_task_code", task.getTaskCode());
			qw.eq("project_code", task.getProjectCode());
			List<PmsTask> subList = baseMapper.selectList(qw);
			if(task.getChildren() == null){
				task.setChildren(new ArrayList<>());
			}
			if(!CollectionUtils.isEmpty(subList)){
				for(PmsTask subTask : subList){
					this.handleTransientVariable(subTask);
					task.getChildren().add(toTree(subTask));
				}
			}
		}
		return task;
	}

	@Override
	public void computeTaskTime(String projectCode) {
		//List<PmsTask> pmsTaskList = pmsTaskService.list(new QueryWrapper<PmsTask>().eq("project_code", projeckCode));
		//Map<String, PmsTask> map = pmsTaskList.stream().collect(Collectors.toMap(PmsTask :: getTaskCode, Function.identity(),(key1, key2) -> key2));
		Map<String, PmsTask> allEditTask = new HashMap<>();
		List<PmsTask> rootTasks = pmsTaskService.list(new QueryWrapper<PmsTask>().eq("project_code", projectCode).eq("parent_task_code", IPmsTaskService.ROOT_PID_VALUE));
		computeTreeTaskTime(rootTasks, allEditTask);
		if(!allEditTask.isEmpty()){
			for(PmsTask entity : allEditTask.values()){
				baseMapper.updateById(entity);
			}
		}
	}

    @Override
    public Result<?> importTasksByExcel(HttpServletRequest request, HttpServletResponse response)throws BusinessException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        String projectCode = multipartRequest.getParameter("projectCode");
        QueryWrapper<PmsProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PmsProject::getProjectCode, projectCode);
        List<PmsProject> projects = pmsProjectService.list(queryWrapper);
        if (CollectionUtils.isEmpty(projects)) {
            throw new BusinessException("项目不存在");
        }
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();// 获取上传文件对象
            ImportParams params = new ImportParams();
            params.setTitleRows(5);
            params.setHeadRows(15);
            try {
                List<PmsTask> list = ExcelImportUtil.importExcel(file.getInputStream(), PmsTask.class, params);
                // 处理项目编码。处理是否有child标识以及上级编码
                BigDecimal totalManHours = new BigDecimal("0");
                if (CollectionUtils.isNotEmpty(list)) {
                    // 声明一个map<taskCode，task对象>，利用引用来处理是否有child以及上级编码问题
                    // 比对原则：如1和1.1，截取最后一个“.”,查看是否在key中，存在则认为value是父级任务
                    Map<String, PmsTask> taskMap = new HashMap<>();
                    for (int i = 0; i < list.size(); i++) {
                        PmsTask pmsTask = list.get(i);
                        list.get(i).setProjectCode(projectCode);
                        list.get(i).setTaskType(PMS_TASK_TYPE);
                        list.get(i).setEndTime(DateUtil.offsetSecond(DateUtil.endOfDay(pmsTask.getEndTime()), -1));
                        // “人天”转换为“工时”
                        BigDecimal manHours = pmsTask.getPlanManHours().multiply(new BigDecimal("8"));
                        pmsTask.setPlanManHours(manHours);
                        if (StringUtils.isBlank(pmsTask.getTaskCode())) {
                            throw new BusinessException("请设置任务编码");
                        }
                        // 截取当前任务的编号，如：“1.1.2”截取为“1.1”
                        int beginIndex = pmsTask.getTaskCode().lastIndexOf(".");
                        if (beginIndex == -1) {
                            // 代表无“.”,属于顶级任务
                            list.get(i).setParentTaskCode("0");
                            totalManHours = totalManHours.add(manHours);
                        }else {
                            String preTaskCode = pmsTask.getTaskCode().substring(0,beginIndex);
                            if (StringUtils.isNotBlank(preTaskCode) && taskMap.containsKey(preTaskCode)) {
                                // 存在父级编码
                                PmsTask parentTask = taskMap.get(preTaskCode);
                                parentTask.setHasChildren("1");

                                list.get(i).setParentTaskCode(preTaskCode);
                            }
                        }
                        taskMap.put(pmsTask.getTaskCode(),list.get(i));

                    }
                }

                pmsTaskService.saveBatch(list);
                // 更新项目总工时
                projects.get(0).setPlanManHours(totalManHours);
                pmsProjectService.updateById(projects.get(0));
                return Result.OK("文件导入成功！数据行数：" + list.size(),null);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return Result.error("文件导入失败:" + e.getMessage());
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.OK("文件导入成功");
    }

    //递归计算时间
	private void computeTreeTaskTime(List<PmsTask> rootTasks,Map<String, PmsTask> allEditTask){
		List<PmsTask> needsEditTask = new ArrayList<>();
		for(PmsTask task : rootTasks){
			List<PmsTask> subTasks = pmsTaskService.list(new QueryWrapper<PmsTask>().eq("parent_task_code", task.getTaskCode()).or().eq("pre_task_code", task.getTaskCode()).or().eq("task_code", task.getParentTaskCode()));
			for(PmsTask subTask : subTasks){
				if(allEditTask.containsKey(subTask.getTaskCode())){
					subTask = allEditTask.get(subTask.getTaskCode());
				}

				//如果是下级关系
				if(task.getTaskCode().equals(subTask.getParentTaskCode())){
					if(task.getStartTime().after(subTask.getStartTime())){
						//当父任务开始时间晚于子任务开始时间
						Long diff = task.getStartTime().getTime() - subTask.getStartTime().getTime();

						subTask.setStartTime(task.getStartTime());
						subTask.setEndTime(new Date(subTask.getEndTime().getTime() + diff));

						//记录修改记录
						allEditTask.put(subTask.getTaskCode(), subTask);
					}

					if (task.getEndTime().before(subTask.getEndTime())){
						//当父任务结束时间早于子任务结束时间

						task.setEndTime(subTask.getEndTime());

						//记录修改记录
						allEditTask.put(task.getTaskCode(), task);
						//对象存入待递归List
						needsEditTask.add(task);
					}

					needsEditTask.add(subTask);
				} else if (task.getEndTime().after(subTask.getStartTime()) && !task.getTaskCode().equals(subTask.getParentTaskCode()) && !task.getParentTaskCode().equals(subTask.getTaskCode())){
					//当前置任务结束时间晚于后置任务开始时间

					Long diff = task.getEndTime().getTime() - subTask.getStartTime().getTime();

					subTask.setStartTime(task.getEndTime());
					subTask.setEndTime(new Date(subTask.getEndTime().getTime() + diff));

					//记录修改记录
					allEditTask.put(subTask.getTaskCode(), subTask);
					//对象存入待递归List
					needsEditTask.add(subTask);
				} else if(task.getParentTaskCode().equals(subTask.getTaskCode())){
					//如果是上级关系
					if(subTask.getStartTime().after(task.getStartTime())){
						//当父任务开始时间晚于子任务开始时间
						Long diff = subTask.getStartTime().getTime() - task.getStartTime().getTime();

						task.setStartTime(subTask.getStartTime());
						task.setEndTime(new Date(task.getEndTime().getTime() + diff));

						//记录修改记录
						allEditTask.put(task.getTaskCode(), task);
						//对象存入待递归List
						needsEditTask.add(task);
					}

					if (subTask.getEndTime().before(task.getEndTime())){
						//当父任务结束时间早于子任务结束时间

						subTask.setEndTime(task.getEndTime());

						//记录修改记录
						allEditTask.put(subTask.getTaskCode(), subTask);
						//对象存入待递归List
						needsEditTask.add(subTask);
					}
				}
			}
			//待递归表有值则 继续递归
			if(CollectionUtils.isNotEmpty(needsEditTask)){
				computeTreeTaskTime(needsEditTask, allEditTask);
			}
		}
	}
}
